home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
GameKit
/
gamekit-1
/
GKSoundStream.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
4KB
|
121 lines
#import <gamekit/gamekit.h>
#import <daymisckit/daymisckit.h>
#import <soundkit/soundkit.h>
#import <sound/sound.h>
#import <sys/param.h>
@implementation GKSoundStream
- init
{ // This method should be avoided.
return [self initStreams:1];
}
- initStreams:(int)nstr
{
int i;
id stream, timeLeft;
if (!_initialized) [super init];
else [self freeObjects];
streamList = [[List alloc] initCount:nstr];
timeLeftList = [[List alloc] initCount:nstr];
device = [[NXSoundOut alloc] init]; // set up sound out device
for (i=0; i<nstr; i++) {
// In 3.1 need to use -initOnDevice:withParameters: to set this up
// right and remove the obsolete play method used down below. *****
stream = [[NXPlayStream alloc] initOnDevice:device];
[stream activate]; // set up our output stream
[streamList addObject:stream];
timeLeft = [[DAYTime alloc] initWithCurrentTime];
[timeLeftList addObject:timeLeft];
}
currentTime = [[DAYTime alloc] init]; // alloc here so only alloc'd once
_initialized = YES; tag = 0;
return self;
}
- playSoundStruct:(SNDSoundStruct *)sound
{ // We assume proper format sounds. Whatever object calls this one
// should assure that any SNDSoundStruct passed in is for a sound
// which is: (1) non-fragmented, (2) 16-bit linear, (3) 22.05 kHz,
// and (4) mono. If you don't stick to this, weird things might
// happen!!! (I don't check for any of this. In the future, I
// probably should do so, and adjust for it. *****
int i, best = 0; // num is stream num we choose
id stream, time = [timeLeftList objectAt:best];
long timeOnStream;
// return if no data to play
if (!sound) return self;
[currentTime initWithCurrentTime];
// find the stream which will be available soonest.
#ifdef NOISYDEBUG
fprintf(stderr, "GKSoundStream: Now is: %s (%d)\n",
[currentTime stringValue], [currentTime microsecond]);
fprintf(stderr, "GKSoundStream: Stream #%d: %s (%d)\n",
0, [time stringValue], [time microsecond]);
#endif
for (i=1; i<[streamList count]; i++) {
id tempTime = [timeLeftList objectAt:i];
#ifdef NOISYDEBUG
fprintf(stderr, "GKSoundStream: Stream #%d: %s (%d)\n",
i, [tempTime stringValue], [tempTime microsecond]);
#endif
if ([time isAfter:tempTime]) {
time = tempTime;
best = i;
}
}
stream = [streamList objectAt:best];
#ifdef NOISYDEBUG
fprintf(stderr, "GKSoundStream: Best time is #%d.\n", best);
#endif
// enqueue the sound for playback
[stream playBuffer:(char *)sound+sound->dataLocation
size:sound->dataSize tag:tag++ channelCount:sound->channelCount
samplingRate:sound->samplingRate];
// estimate how long sound is to be on stream:
// (based on 16it 22050 Hz mono sounds.)
timeOnStream = (sound->dataSize / 2) * 45.3514739229;
// set up when stream will be finished.
if ([currentTime isAfter:time]) [time initWithCurrentTime]; // gap in play
// (above 'if' fails if stuff is on the stream right now. Needed because
// if there was a gap in stream playback, then we start playing NOW, but
// it the stream is busy, then we start when it finishes.) Note that
// realistically, I should add in a fudge factor if the if is true since
// the stream doesn't start to play _immediately_. This seems to be
// close enough for my purposes, though. Eventually, I may play with
// adding in a fudge factor to try and take this into account. *****
// Note: the stream delegate method - soundStream:didStartBuffer:
// might be adequate here.
[time addMicroseconds:timeOnStream];
#ifdef NOISYDEBUG
fprintf(stderr, "GKSoundStream: On stream for %ld usec.\n", timeOnStream);
fprintf(stderr, "GKSoundStream: Estimate of time when done: %s (%d)\n\n",
[time stringValue], [time microsecond]);
#endif
return time;
}
- freeObjects
{
[timeLeftList freeObjects];
[timeLeftList free];
[streamList freeObjects];
[streamList free];
[device free];
[currentTime free];
return self;
}
- free
{
[self freeObjects];
return nil;
}
- streamList { return streamList; }
- timeLeftList { return timeLeftList; }
@end